﻿using System;
using System.Linq.Expressions;

namespace Emico.Linq.Criterion
{
    public static class ExpressionExtends
    {
        #region And

        public static IExpression<T> And<T>(this IExpression<T> lhs, IExpression<T> rhs)
            where T : class
        {
            return new AndExpression<T>(lhs, rhs);
        }

        public static IExpression<T> And<T>(this IExpression<T> lhs, Expression<Func<T, bool>> predicate)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T>(predicate);
            return new AndExpression<T>(lhs, rhs);
        }

        public static IExpression<T> And<T, A0>(this IExpression<T> lhs, Expression<Func<T, A0, bool>> predicate, A0 arg0)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0>(predicate, arg0);
            return new AndExpression<T>(lhs, rhs);
        }

        public static IExpression<T> And<T, A0, A1>(this IExpression<T> lhs, Expression<Func<T, A0, A1, bool>> predicate, A0 arg0, A1 arg1)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0, A1>(predicate, arg0, arg1);
            return new AndExpression<T>(lhs, rhs);
        }

        public static IExpression<T> And<T, A0, A1, A2>(this IExpression<T> lhs, Expression<Func<T, A0, A1, A2, bool>> predicate, A0 arg0, A1 arg1, A2 arg2)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0, A1, A2>(predicate, arg0, arg1, arg2);
            return new AndExpression<T>(lhs, rhs);
        }

        public static IExpression<T> And<T, A0, A1, A2, A3>(this IExpression<T> lhs, Expression<Func<T, A0, A1, A2, A3, bool>> predicate, A0 arg0, A1 arg1, A2 arg2, A3 arg3)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0, A1, A2, A3>(predicate, arg0, arg1, arg2, arg3);
            return new AndExpression<T>(lhs, rhs);
        }

        #endregion

        #region Or

        public static IExpression<T> Or<T>(this IExpression<T> lhs, IExpression<T> rhs)
            where T : class
        {
            return new OrExpression<T>(lhs, rhs);
        }

        public static IExpression<T> Or<T>(this IExpression<T> lhs, Expression<Func<T, bool>> predicate)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T>(predicate);
            return new OrExpression<T>(lhs, rhs);
        }

        public static IExpression<T> Or<T, A0>(this IExpression<T> lhs, Expression<Func<T, A0, bool>> predicate, A0 arg0)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0>(predicate, arg0);
            return new OrExpression<T>(lhs, rhs);
        }

        public static IExpression<T> Or<T, A0, A1>(this IExpression<T> lhs, Expression<Func<T, A0, A1, bool>> predicate, A0 arg0, A1 arg1)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0, A1>(predicate, arg0, arg1);
            return new OrExpression<T>(lhs, rhs);
        }

        public static IExpression<T> Or<T, A0, A1, A2>(this IExpression<T> lhs, Expression<Func<T, A0, A1, A2, bool>> predicate, A0 arg0, A1 arg1, A2 arg2)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0, A1, A2>(predicate, arg0, arg1, arg2);
            return new OrExpression<T>(lhs, rhs);
        }

        public static IExpression<T> Or<T, A0, A1, A2, A3>(this IExpression<T> lhs, Expression<Func<T, A0, A1, A2, A3, bool>> predicate, A0 arg0, A1 arg1, A2 arg2, A3 arg3)
            where T : class
        {
            LambdaExpression<T> rhs = new LambdaExpression<T, A0, A1, A2, A3>(predicate, arg0, arg1, arg2, arg3);
            return new OrExpression<T>(lhs, rhs);
        }

        #endregion
    }
}
